from fastapi import FastAPI, Request, Form, HTTPException, Body
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import os
from pathlib import Path
from typing import Optional, Dict, Any
import json
import uuid
from datetime import datetime

app = FastAPI(title="Markdown Editor with Mermaid & ECharts")

# 添加CORS中间件以避免跨域问题
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 确保静态文件和模板目录存在
Path("static").mkdir(exist_ok=True)
Path("templates").mkdir(exist_ok=True)
Path("content").mkdir(exist_ok=True)  # 用于存储文档的目录
Path("content/metadata").mkdir(exist_ok=True, parents=True)  # 用于存储文档元数据的目录

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")

# 设置模板目录
templates = Jinja2Templates(directory="templates")


@app.get("/", response_class=HTMLResponse)
async def get_editor(request: Request, document_id: Optional[str] = None):
    """返回包含 Vditor 编辑器的 HTML 页面"""
    content = ""
    document_name = "无标题文档"

    if document_id and document_id != "new":
        # 尝试加载现有文档
        document_path = Path(f"content/{document_id}.md")
        if document_path.exists():
            content = document_path.read_text(encoding="utf-8")

            # 加载文档元数据
            metadata_path = Path(f"content/metadata/{document_id}.json")
            if metadata_path.exists():
                try:
                    metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
                    document_name = metadata.get("name", f"文档_{document_id}")
                except:
                    document_name = f"文档_{document_id}"

    return templates.TemplateResponse("editor.html", {
        "request": request,
        "initial_content": content,
        "document_id": document_id or "new",
        "document_name": document_name
    })


@app.post("/new-document")
async def create_new_document():
    """创建一个新文档并返回文档ID"""
    document_id = str(uuid.uuid4())[:8]

    # 创建文档元数据
    metadata = {
        "id": document_id,
        "name": "新文档",
        "created_at": datetime.now().isoformat(),
        "updated_at": datetime.now().isoformat()
    }

    metadata_path = Path(f"content/metadata/{document_id}.json")
    metadata_path.write_text(json.dumps(metadata, ensure_ascii=False), encoding="utf-8")

    # 创建空文档
    document_path = Path(f"content/{document_id}.md")
    document_path.write_text("", encoding="utf-8")

    return JSONResponse({
        "status": "success",
        "document_id": document_id,
        "redirect_url": f"/?document_id={document_id}"
    })


@app.post("/save-document/{document_id}")
async def save_document(
        document_id: str,
        request: Request,
        content: Optional[str] = Form(None)
):
    """保存文档内容，支持表单和JSON两种格式"""
    # 如果没有从表单获取到内容，尝试从JSON请求体获取
    if content is None:
        try:
            body = await request.json()
            content = body.get("content")
            name = body.get("name")
        except:
            raise HTTPException(
                status_code=422,
                detail="无法解析请求内容，请提供有效的content字段"
            )
    else:
        # 如果是表单格式，尝试从表单获取名称
        form_data = await request.form()
        name = form_data.get("name")

    if content is None:
        raise HTTPException(
            status_code=422,
            detail="请求必须包含content字段"
        )

    try:
        # 保存文档内容
        document_path = Path(f"content/{document_id}.md")
        document_path.write_text(content, encoding="utf-8")

        # 更新文档元数据
        metadata_path = Path(f"content/metadata/{document_id}.json")
        if metadata_path.exists():
            metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
            metadata["updated_at"] = datetime.now().isoformat()
            # 如果提供了新名称，更新名称
            if name:
                metadata["name"] = name
            metadata_path.write_text(json.dumps(metadata, ensure_ascii=False), encoding="utf-8")
        else:
            # 如果元数据不存在，创建新的元数据
            metadata = {
                "id": document_id,
                "name": name or f"文档_{document_id}",
                "created_at": datetime.now().isoformat(),
                "updated_at": datetime.now().isoformat()
            }
            metadata_path.write_text(json.dumps(metadata, ensure_ascii=False), encoding="utf-8")

        return JSONResponse({
            "status": "success",
            "document_id": document_id,
            "message": "文档保存成功"
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"保存失败: {str(e)}")


@app.get("/list-documents")
async def list_documents():
    """列出所有保存的文档及其元数据"""
    documents = []
    content_dir = Path("content")
    metadata_dir = Path("content/metadata")

    # 获取所有文档文件
    md_files = list(content_dir.glob("*.md"))

    for file_path in md_files:
        document_id = file_path.stem

        # 读取文档内容
        with open(file_path, "r", encoding="utf-8") as f:
            content = f.read()

        # 读取元数据
        metadata_path = metadata_dir / f"{document_id}.json"
        if metadata_path.exists():
            try:
                with open(metadata_path, "r", encoding="utf-8") as f:
                    metadata = json.load(f)
            except:
                # 如果元数据文件损坏，创建默认元数据
                metadata = {
                    "id": document_id,
                    "name": f"文档_{document_id}",
                    "created_at": datetime.fromtimestamp(file_path.stat().st_ctime).isoformat(),
                    "updated_at": datetime.fromtimestamp(file_path.stat().st_mtime).isoformat()
                }
                with open(metadata_path, "w", encoding="utf-8") as f:
                    json.dump(metadata, f, ensure_ascii=False)
        else:
            # 如果没有元数据，创建默认元数据
            metadata = {
                "id": document_id,
                "name": f"文档_{document_id}",
                "created_at": datetime.fromtimestamp(file_path.stat().st_ctime).isoformat(),
                "updated_at": datetime.fromtimestamp(file_path.stat().st_mtime).isoformat()
            }
            with open(metadata_path, "w", encoding="utf-8") as f:
                json.dump(metadata, f, ensure_ascii=False)

        documents.append({
            "id": document_id,
            "name": metadata.get("name", f"文档_{document_id}"),
            "preview": content[:100] + "..." if len(content) > 100 else content,
            "size": len(content),
            "created_at": metadata.get("created_at"),
            "updated_at": metadata.get("updated_at")
        })

    # 按更新时间排序（最新的在前）
    documents.sort(key=lambda x: x.get("updated_at", ""), reverse=True)

    return JSONResponse({"documents": documents})


@app.delete("/document/{document_id}")
async def delete_document(document_id: str):
    """删除文档及其元数据"""
    try:
        # 删除文档文件
        document_path = Path(f"content/{document_id}.md")
        if document_path.exists():
            document_path.unlink()

        # 删除元数据文件
        metadata_path = Path(f"content/metadata/{document_id}.json")
        if metadata_path.exists():
            metadata_path.unlink()

        return JSONResponse({
            "status": "success",
            "message": "文档删除成功"
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"删除失败: {str(e)}")


@app.post("/document/{document_id}/rename")
async def rename_document(document_id: str, request: Request):
    """重命名文档"""
    try:
        # 获取新名称
        body = await request.json()
        new_name = body.get("name")

        if not new_name:
            raise HTTPException(status_code=422, detail="请提供新的文档名称")

        # 更新元数据
        metadata_path = Path(f"content/metadata/{document_id}.json")
        if metadata_path.exists():
            with open(metadata_path, "r", encoding="utf-8") as f:
                metadata = json.load(f)

            metadata["name"] = new_name
            metadata["updated_at"] = datetime.now().isoformat()

            with open(metadata_path, "w", encoding="utf-8") as f:
                json.dump(metadata, f, ensure_ascii=False)
        else:
            # 如果元数据不存在，创建新的元数据
            metadata = {
                "id": document_id,
                "name": new_name,
                "created_at": datetime.now().isoformat(),
                "updated_at": datetime.now().isoformat()
            }
            with open(metadata_path, "w", encoding="utf-8") as f:
                json.dump(metadata, f, ensure_ascii=False)

        return JSONResponse({
            "status": "success",
            "message": "文档重命名成功"
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"重命名失败: {str(e)}")


@app.get("/document/{document_id}/content")
async def get_document_content(document_id: str):
    """获取文档内容和元数据"""
    try:
        # 获取文档内容
        document_path = Path(f"content/{document_id}.md")
        if not document_path.exists():
            raise HTTPException(status_code=404, detail="文档不存在")
            
        with open(document_path, "r", encoding="utf-8") as f:
            content = f.read()

        # 获取文档元数据
        metadata_path = Path(f"content/metadata/{document_id}.json")
        if metadata_path.exists():
            with open(metadata_path, "r", encoding="utf-8") as f:
                metadata = json.load(f)
        else:
            metadata = {
                "id": document_id,
                "name": f"文档_{document_id}",
                "created_at": datetime.fromtimestamp(document_path.stat().st_ctime).isoformat(),
                "updated_at": datetime.fromtimestamp(document_path.stat().st_mtime).isoformat()
            }

        return JSONResponse({
            "status": "success",
            "content": content,
            "metadata": metadata
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取文档失败: {str(e)}")


@app.get("/document/{document_id}/metadata")
async def get_document_metadata(document_id: str):
    """获取文档元数据"""
    try:
        metadata_path = Path(f"content/metadata/{document_id}.json")
        if metadata_path.exists():
            with open(metadata_path, "r", encoding="utf-8") as f:
                metadata = json.load(f)

            return JSONResponse({
                "status": "success",
                "metadata": metadata
            })
        else:
            raise HTTPException(status_code=404, detail="文档不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取元数据失败: {str(e)}")


if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)